package de.openkanban.server.dao.impl;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import de.openkanban.server.dao.ActivityDao;
import de.openkanban.server.domain.Activity;
import de.openkanban.server.domain.Kanban;
import de.openkanban.shared.util.StatusCodes;

/**
 * jpa implementation of activity data access object
 */
@Repository
public class ActivityDaoImpl implements ActivityDao {

	@PersistenceContext
	private EntityManager entityManager;

	@Override
	@Transactional
	public Activity createActivity(Activity activity) {
		entityManager.persist(activity);
		return activity;
	}

	@Override
	public Activity getActivity(Long activityId) {
		return entityManager.find(Activity.class, activityId);
	}

	@Override
	public Activity getActivityByKanbanId(Long kanbanId) {
		Query query = entityManager.createQuery("SELECT a FROM Activity a JOIN a.kanbans k WHERE k.kanbanId=:kanbanId");
		query.setParameter("kanbanId", kanbanId);

		return (Activity) query.getSingleResult();
	}

	@Override
	@Transactional
	public Kanban addKanbanToActivity(Long parentActivityId, Kanban newKanban) {
		Activity parentActivity = entityManager.find(Activity.class, parentActivityId);
		if (parentActivity != null) {
			entityManager.persist(newKanban);
			parentActivity.getKanbans().add(newKanban);
			return newKanban;
		}
		return null;
	}

	@Override
	public List<Activity> getAll() {
		Query query = entityManager.createQuery("SELECT a FROM Activity a");
		@SuppressWarnings("unchecked")
		List<Activity> activityList = query.getResultList();
		return activityList;
	}

	@Override
	@Transactional
	public StatusCodes removeActivity(Activity activity) {
		entityManager.remove(activity);
		return StatusCodes.OK;
	}

	@Override
	@Transactional
	public Activity updateActivity(Activity activity) {
		Activity activityToUpdate = entityManager.find(Activity.class, activity.getActivityId());
		activityToUpdate.setActivityName(activity.getActivityName());
		activityToUpdate.setWipLimit(activity.getWipLimit());		
		return activityToUpdate;
	}

	@Override
	@Transactional
	public Kanban moveKanbanToActivity(Long parentActivityId, Long kanbanId) {
		Query query = entityManager.createQuery("SELECT a FROM Activity a JOIN a.kanbans k WHERE k.kanbanId=:kanbanId");
		query.setParameter("kanbanId", kanbanId);
		Activity sourceActivity = (Activity) query.getSingleResult();
		Activity destActivity = entityManager.find(Activity.class, parentActivityId);
		Kanban kanban = entityManager.find(Kanban.class, kanbanId);
		if (sourceActivity != null && destActivity != null && kanban != null) {
			sourceActivity.getKanbans().remove(kanban);
			destActivity.getKanbans().add(kanban);
			entityManager.merge(sourceActivity);
			entityManager.merge(destActivity);
			return kanban;
		}
		return null;
	}

	@Override
	public List<Activity> getAllByBoardId(Long parentBoardId) {
		Query query = entityManager.createQuery("SELECT a FROM Board b JOIN b.activities a WHERE boardId=:boardId");
		query.setParameter("boardId", parentBoardId);
		@SuppressWarnings("unchecked")
		List<Activity> activityList = query.getResultList();
		return activityList;
	}

	@Override
	public List<Activity> getActivityRange(Long boardId, Long beginActivityId, Long endActivityId) {
		Query query = entityManager
				.createQuery("SELECT a FROM Board b JOIN b.activities a WHERE b.boardId=:boardId AND ((a.activityId BETWEEN :beginActivityId AND :endActivityId) OR (a.activityId BETWEEN :endActivityId AND :beginActivityId))");
		query.setParameter("boardId", boardId);
		query.setParameter("beginActivityId", beginActivityId);
		query.setParameter("endActivityId", endActivityId);

		@SuppressWarnings("unchecked")
		List<Activity> resultList = (List<Activity>) query.getResultList();
		return resultList;
	}
}
